#include <stdio.h>
#include <windows.h>
#include "pThreads/semaphore.h"
#include <vector>
#include "CSemaphore.h"
#include "CBlowfish.h"
#include "CConsole.h"

FILE*         SubkeyFile;

CBlowfish::CBlowfish(){

}
	
CBlowfish::~CBlowfish(){

}

short CBlowfish::opensubkeyfile(void) /* read only */
{
   short error;

   error = noErr;

   if((SubkeyFile = fopen(subkeyfilename,"rb")) == NULL) {
      error = DATAERROR;
   }
 
   return error;
}

unsigned long TT(unsigned long working, unsigned long * S){
	return (((S[256+((working>>8)&0xff)]&1)^32)+((S[768+(working >> 24)]&1)^32)+S[512+((working >> 16)&0xff)]+S[working&0xff]);
}

void CBlowfish::encipher(unsigned long *xl, unsigned long *xr, unsigned long * P, unsigned long * S)
{
   unsigned long  Xl;
   unsigned long  Xr;
   unsigned long  temp;
   short          i;

   Xl = *xl;
   Xr = *xr;

   for (i = 0; i < N; ++i) {
      Xl = Xl ^ P[i];
      Xr = TT(Xl, S) ^ Xr;

      temp = Xl;
      Xl = Xr;
      Xr = temp;
   }

   temp = Xl;
   Xl = Xr;
   Xr = temp;

   Xr = Xr ^ P[N];
   Xl = Xl ^ P[N + 1];
  
   *xl = Xl;
   *xr = Xr;
}

void CBlowfish::decipher(unsigned long *xl, unsigned long *xr, unsigned long * P, unsigned long * S)
{
   unsigned long  Xl;
   unsigned long  Xr;
   unsigned long  temp;
   short          i;

   Xl = *xl;
   Xr = *xr;

   for (i = N + 1; i > 1; --i) {
      Xl = Xl ^ P[i];
      Xr = TT(Xl, S) ^ Xr;

      /* Exchange Xl and Xr */
      temp = Xl;
      Xl = Xr;
      Xr = temp;
   }

   /* Exchange Xl and Xr */
   temp = Xl;
   Xl = Xr;
   Xr = temp;

   Xr = Xr ^ P[1];
   Xl = Xl ^ P[0];

   *xl = Xl;
   *xr = Xr;
}

unsigned long * CBlowfish::init(char key[], short keybytes, unsigned long * P, unsigned long * S)
{
   short          i;
   short          j;
   short          k;
   short          error;
   short          numread;
   unsigned long  data;
   unsigned long  datal;
   unsigned long  datar;

   /* First, open the file containing the array initialization data */
   error = opensubkeyfile();
   if (error == noErr) {
      for (i = 0; i < N + 2; ++i) {
	 numread = (short)fread(&data, 4, 1, SubkeyFile);
   #ifdef little_endian      /* Eg: Intel   We want to process things in byte   */
			   /*   order, not as rearranged in a longword          */
	 data = ((data & 0xFF000000) >> 24) |
		((data & 0x00FF0000) >>  8) |
		((data & 0x0000FF00) <<  8) |
		((data & 0x000000FF) << 24);
   #endif

	 if (numread != 1) {
	    return NULL;
	 } else {
	    P[i] = data;
	 }
      }

      for (i = 0; i < 4; ++i) {
	 for (j = 0; j < 256; ++j) {
	     numread = (short)fread(&data, 4, 1, SubkeyFile);

   #ifdef little_endian      /* Eg: Intel   We want to process things in byte   */
			   /*   order, not as rearranged in a longword          */
	    data = ((data & 0xFF000000) >> 24) |
		   ((data & 0x00FF0000) >>  8) |
		   ((data & 0x0000FF00) <<  8) |
		   ((data & 0x000000FF) << 24);
   #endif

	     if (numread != 1) {
	       return NULL;
	    } else {
	       S[i*256+j] = data;
	    }
	 }
      }

      fclose(SubkeyFile);

      j = 0;
      for (i = 0; i < N + 2; ++i) {
	 data = 0x00000000;
	 for (k = 0; k < 4; ++k) {
	    data = (data << 8) | key[j];
	    j = j + 1;
	    if (j >= keybytes) {
	       j = 0;
	    }
	 }
	 P[i] = P[i] ^ data;
      }

	datal = 0x00000000;
      datar = 0x00000000;

      for (i = 0; i < N + 2; i += 2) {
	 encipher(&datal, &datar, P, S);

	 P[i] = datal;
	 P[i + 1] = datar;
      }

      for (i = 0; i < 4; ++i) {
	 for (j = 0; j < 256; j += 2) {

	    encipher(&datal, &datar, P, S);
   
	    S[i*256+j] = datal;
	    S[i*256+j + 1] = datar;
	 }
      }
   } else {
	   CConsole::outErr("Unable to open subkey initialization file : %d\n", error);
   }

   return P;
}

